import json
from datetime import datetime

from sqlalchemy import and_
import math
import numpy as np
from typing import Dict, List
import logging as log
from app.database import convert
from app.exts import ironman_redis as redis, influxdb
from app.models.po.lugang.lugang_original_po import LuGangActivinessPredictPO, LuGangActivinessDataPO
from app.services.business.gaolu_diagnose.ind import ind_cls_dict
from app.services.business.gaolu_diagnose.ind.abstract_ind import AbstractInd
from app.services.models.lugang_activiness_short_model import lugang_activiness_short
import logging
from app.exts import mysql_pool
from app.utils import date_util
from app.utils.thread import SubThread, CountDownLatch
from datetime import timedelta


def dump_lugang_activeness_short():
    """
    炉缸活跃性短期数据准备
    :return:
    """
    threads = []
    inds = ['CG_LT_GL_GL04_DWDB', 'CG_LT_GL_GL04_FYL',
            'CG_LT_GL_GL04_RLB', 'CG_LT_GL_GL04_TSWD',
            'CG_LT_GL_GL04_LFLL']

    latch = CountDownLatch(len(inds))
    start = date_util.get_start_of_day(datetime.now()-timedelta(days=3))
    end = date_util.get_end_of_day(datetime.now())

    def func(thread):
        influxdb_client = influxdb.get_client()
        name = thread.name
        params = thread.params
        if name in ind_cls_dict.keys():
            try:
                cls = ind_cls_dict[name]
                instance: AbstractInd = cls(influxdb_client, params, mysql_pool)
                value = instance.get_result()
                thread.result = value
            except Exception as e:
                log.error("fail to get lugang_activeness_short result of {}. {}".format(name, e), exc_info=1)
        thread.latch.countDown()

    for ind in inds:
        dt_start_tz = date_util.dt_to_str(
            start - timedelta(hours=8),
            '%Y-%m-%dT%H:%M:%SZ')
        dt_end_tz = date_util.dt_to_str(
            end - timedelta(hours=8),
            '%Y-%m-%dT%H:%M:%SZ')
        params = dict(ind_name=ind,
                      influxdb=influxdb,
                      dt_start_tz=dt_start_tz,
                      dt_end_tz=dt_end_tz)
        thread = SubThread(ind, latch, params, func)
        threads.append(thread)
        thread.start()

    latch.await()
    now = datetime.now()
    hour_end = datetime(now.year, now.month, now.day, now.hour, 59, 59)

    for thread in threads:

        hour_record = convert.query(LuGangActivinessDataPO,
                                    LuGangActivinessDataPO.name == thread.name,
                                    LuGangActivinessDataPO.date_time == hour_end,
                                    LuGangActivinessDataPO.type == 'short',
                                    LuGangActivinessDataPO.level == 'hour').first()
        if hour_record is None:
            day_record: LuGangActivinessDataPO = LuGangActivinessDataPO()
            day_record.level = "hour"
            day_record.type = "short"
            day_record.name = thread.name
            day_record.value = thread.result
            day_record.date_time = hour_end
            day_record.gmt_create = now
            day_record.gmt_modified = now
            convert.add_one(day_record)
        else:
            convert.update_model(hour_record, dict(value=thread.result, gmt_modified=datetime.now()))


def dump_lugang_activeness_predict_short():
    now = datetime.now()
    hour_end = datetime(now.year, now.month, now.day, now.hour, 59, 59)

    histories: List[LuGangActivinessDataPO] = convert.query(LuGangActivinessDataPO,
                                                            LuGangActivinessDataPO.date_time == hour_end,
                                                            LuGangActivinessDataPO.type == 'short',
                                                            LuGangActivinessDataPO.level == 'hour').all()

    a = {history.name: history.value for history in histories}
    CG_LT_GL_GL04_DWDB = a.get("CG_LT_GL_GL04_DWDB", 0)
    CG_LT_GL_GL04_FYL = a.get("CG_LT_GL_GL04_FYL", 0)
    CG_LT_GL_GL04_TSWD = a.get("CG_LT_GL_GL04_TSWD", 0)
    CG_LT_GL_GL04_LFLL = a.get("CG_LT_GL_GL04_LFLL", 0)
    CG_LT_GL_GL04_RLB = a.get("CG_LT_GL_GL04_RLB", 0)

    current = round((1.21 * CG_LT_GL_GL04_LFLL * CG_LT_GL_GL04_FYL / 60) / 1481.544 + 1.5 * (CG_LT_GL_GL04_RLB - 483) +
                    2 * (CG_LT_GL_GL04_TSWD - 1400) + 5 * CG_LT_GL_GL04_DWDB / 10 + 1100)

    model_input = get_model_input(histories,
                                  ['CG_LT_GL_GL04_FYL','CG_LT_GL_GL04_DWDB',
                                   'CG_LT_GL_GL04_LFLL','CG_LT_GL_GL04_RLB','CG_LT_GL_GL04_TSWD'])
    log.info("lugang_activiness_short input is {}".format(json.dumps(model_input)))

    predict = lugang_activiness_short.process(model_input)

    day_record = convert.query(LuGangActivinessPredictPO,
                               LuGangActivinessPredictPO.date_time == hour_end,
                               LuGangActivinessPredictPO.type == 'short',
                               LuGangActivinessPredictPO.level == 'hour').first()

    if day_record is None:
        day_record = LuGangActivinessPredictPO()
        day_record.date_time = hour_end
        day_record.current = current
        day_record.predict = predict
        day_record.type = 'short'
        day_record.level = 'hour'
        day_record.gmt_create = now
        day_record.gmt_create = now
        convert.add_one(day_record)
    else:
        convert.update_model(day_record, dict(current=current, predict=predict, gmt_modified=datetime.now()))


def get_model_input(datas: List[LuGangActivinessDataPO], columns):
    data_dict = {data.name: data.value for data in datas}

    return {column: data_dict.get(column, 0) for column in columns}
